package org.moonshiner.controller.security;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AESFileEncryptor extends FileEncryptor {

	public void doCrypt(String password, InputStream in, OutputStream out,
			int cipherMode) {

		byte[] key = getKey(password);

		key = getShaMessageDigest(key);

		SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");

		AlgorithmParameterSpec parameterSpec = new IvParameterSpec(key);

		Cipher cipher = getChiper("AES/CBC/PKCS5Padding");
		if (cipherMode == Cipher.ENCRYPT_MODE) {
			try {
				ecnrypt(in, out, cipherMode, secretKeySpec, parameterSpec,
						cipher);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			}
		} else if (cipherMode == Cipher.DECRYPT_MODE) {
			try {
				decrypt(in, out, cipherMode, secretKeySpec, parameterSpec,
						cipher);
			} catch (InvalidKeyException e) {
				e.printStackTrace();
			} catch (InvalidAlgorithmParameterException e) {
				e.printStackTrace();
			}
		}

	}

	private byte[] getShaMessageDigest(byte[] key) {
		MessageDigest sha = null;
		try {
			sha = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		key = sha.digest(key);
		key = Arrays.copyOf(key, 16);
		return key;
	}

	private byte[] getKey(String password) {
		byte[] key = null;
		try {
			key = password.getBytes("UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return key;
	}

	private void decrypt(InputStream in, OutputStream out, int cipherMode,
			SecretKeySpec secretKeySpec, AlgorithmParameterSpec parameterSpec,
			Cipher cipher) throws InvalidKeyException,
			InvalidAlgorithmParameterException {
		cipher.init(cipherMode, secretKeySpec, parameterSpec);
		CipherOutputStream cipherOutputStream = new CipherOutputStream(out,
				cipher);
		doCopy(in, cipherOutputStream);
	}

	private void ecnrypt(InputStream in, OutputStream out, int cipherMode,
			SecretKeySpec secretKeySpec, AlgorithmParameterSpec parameterSpec,
			Cipher cipher) throws InvalidKeyException,
			InvalidAlgorithmParameterException {
		cipher.init(cipherMode, secretKeySpec, parameterSpec);
		CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
		doCopy(cipherInputStream, out);
	}

}
